
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include "task.hpp"

class Channel
{
public:
    Channel(string& name, int wfd, pid_t sub_pid)
        :_name(name)
        ,_wfd(wfd)
        ,_sub_process_pid(sub_pid)
    {}

    void Debug()
    {
        cout << "create pipe successfully, name is " << _name << endl;
    }

    void Close(){ close(_wfd); }


    int getwfd(){ return _wfd; } 
    string getname(){ return _name; }
    pid_t getpid() {return _sub_process_pid; }


    ~Channel()
    {}
private:
    string _name;
    int _wfd;
    pid_t _sub_process_pid; 
};

class ProcessPool
{
public:
    ProcessPool(int process_num = 5)
        :_process_num(process_num)
    {}

    int create_process(work_t work)
    {
        vector<int> fds;
        for (int i = 0; i < _process_num; ++i)
        {
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            pid_t id = fork();
            if(n < 0)
            {
                printf("创建管道失败\n");
                return 2;
            }
            if (id == 0)
            {
                // r
                close(pipefd[1]);
                // 关闭子进程中指向其他管道的写端
                printf("close ");
                for(int e : fds)
                {
                    close(e);
                    printf("%d ", e);
                }
                printf("\n");
                while(1)
                {
                    uint32_t task_node = 0;
                    //printf("read , pipefd[0] = %d\n", pipefd[0]);
                    ssize_t n = read(pipefd[0], &task_node, sizeof(task_node));
                    if (n == sizeof(task_node))
                    {
                        if (task_node >= 3)
                            continue;
                        task[task_node](1);
                    }
                    else if(n == 0)
                    {
                        printf("subprocess %d quit...\n", i);
                        break;
                    }
                    sleep(1);
                }
                exit(0);
            }
            
            // w
            close(pipefd[0]);
            string name = "process " + to_string(i);
            _Channels.push_back(Channel(name, pipefd[1], id));
            fds.push_back(pipefd[1]);
        }
        return 0;
    }

    void KillAllSubProcess()
    {
        for(auto& channel : _Channels)
        {
            channel.Close();
            cout << channel.getname() << " close..." << endl;
        }   
        // cout << _Channels[0].getname() << " close..." << endl;
        // _Channels[0].Close();
    }

    void Debug()
    {
        for(auto& cl : _Channels)
        {
            cl.Debug();
        }
    }

    Channel& ChooseChannel()
    {
        static int i = 0;
        Channel& channel = _Channels[i++];
        i %= _process_num;
        return channel;
    }

    void Wait()
    {
        for(auto& cl : _Channels)
        {
            pid_t pid = cl.getpid();
            int rid = waitpid(pid, nullptr, 0);
            if(rid == pid)
            {
                printf("等待成功, name is %s, pid is %d\n", cl.getname().c_str(),pid);

            }
            else if(rid < 0)
            {
                printf("等待失败\n");
                cout << strerror(errno) << endl;
            }
        }
    }

    ~ProcessPool()
    {}

private:
    int _process_num;
    vector<Channel> _Channels;
};

void CtrlProcess(ProcessPool* processpool_ptr, int cnt)
{
    while(cnt--)
    {
        Channel channel = processpool_ptr->ChooseChannel();
        cout << "选择了一个进程: " << channel.getname();
        printf(" wfd is %d, pid is %d\n", channel.getwfd(), channel.getpid());

        uint32_t task_node = getTaskNode();
        cout << "写入一个信息: " << task_node << endl;

        write(channel.getwfd(), &task_node, sizeof(task_node));
        
        sleep(1);
    }
}

//./processpool 5
int main(int argc, char *argv[])
{
     if (argc != 2)
    {
        cout << "参数个数错误" << endl;
        return 1;
    }

    int process_num = stoi(argv[1]);
    if (process_num <= 0)
    {
        cout << "参数设置错误" << endl;
        return 2;
    }
    srand((unsigned int)time(nullptr));

    ProcessPool* processpool_ptr = new ProcessPool(process_num);
    work_t work = Work;
    processpool_ptr->create_process(work);
    processpool_ptr->Debug();

    //控制子进程执行任务
    CtrlProcess(processpool_ptr, 5);

    processpool_ptr->KillAllSubProcess();

    processpool_ptr->Wait();

    delete processpool_ptr;
    return 0;  
}